package com.generator.demo.utils.generatorUtil;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.*;

/**
 * @author hujunyu
 * @date 2021/8/16
 */
public class MybatisPlusGenerator {


    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + "：");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "！");
    }

    public static String[] create(GeneratorProperties generatorProperties) {
        if (generatorProperties == null) {
            throw new RuntimeException("代码生成工具的配置信息为空！");
        }
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        String PATH = System.getProperty("user.dir");
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(PATH + generatorProperties.getModuleName() + "/src/main/java");
        gc.setAuthor(generatorProperties.getCreateUser());
        gc.setOpen(false);
        //是否覆盖文件
        gc.setFileOverride(generatorProperties.getFileOverride());
        //去掉Service接口的首字母I
        gc.setServiceName("%sService");
        //主键策略
        gc.setIdType(IdType.NONE);
        //定义生成的实体类中日期类型
        gc.setDateType(DateType.ONLY_DATE);
        // xml resultmap
        gc.setBaseResultMap(true);
        // xml columlist
        gc.setBaseColumnList(true);
        //实体属性 Swagger2 注解
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl(generatorProperties.getUrl());
        dsc.setDriverName(generatorProperties.getDriver());
        dsc.setUsername(generatorProperties.getUser());
        dsc.setPassword(generatorProperties.getPassword());
        dsc.setTypeConvert(new MySqlTypeConvert() {
            // 自定义数据库表字段类型转换【可选】
            @Override
            public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
                if (fieldType.toLowerCase().contains("datetime")) {
                    return DbColumnType.DATE;
                }
                return super.processTypeConvert(globalConfig, fieldType);
            }

        });
        dsc.setDbQuery(new MySqlQuery() {
            /**
             * 重写父类预留查询自定义字段<br>
             * 这里查询的 SQL 对应父类 tableFieldsSql 的查询字段，默认不能满足你的需求请重写它<br>
             * 模板中调用：  table.fields 获取所有字段信息，
             * 然后循环字段获取 field.customMap 从 MAP 中获取注入字段如下  NULL 或者 PRIVILEGES
             */
            @Override
            public String[] fieldCustom() {
                return new String[]{"NULL", "PRIVILEGES"};
            }
        });
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent(generatorProperties.getParentPackage());//父包
        //entity层包
        pc.setEntity(generatorProperties.getEntityPackage());
        //mapper层包
        pc.setMapper(generatorProperties.getMapperPackage());
        //service层包
        pc.setService(generatorProperties.getServicePackage());
        //serviceImpl层包
        pc.setServiceImpl(generatorProperties.getServiceImplPackage());
        mpg.setPackageInfo(pc);

        //需要生成代码的表
        String[] tables = scanner("表名，多个英文逗号分割").split(",");
        Map<String, Object> map = new HashMap<>();
        //设置‘$’,xml需要
        map.put("dl", "$");
        //设置‘#’,xml需要
        map.put("jing", "#");
        //设置‘{’,xml需要
        map.put("left", "{");
        //设置‘}’,xml需要
        map.put("right", "}");
        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            //自定义属性注入:abc
            //在.ftl(或者是.vm)模板中，通过${cfg.abc}获取属性
            @Override
            public void initMap() {
                //设置自定义属性map
                this.setMap(map);
            }
        };

        // 如果模板引擎是 freemarker
        String templatePath = generatorProperties.getTemplatePath();
        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
                return PATH + generatorProperties.getModuleName() + "/src/main/resources/mapper/"
                        + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        //取消默认mapper的生成地址
        templateConfig.setXml(null);
        templateConfig.setController("");
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //使用lombok注解
        strategy.setEntityLombokModel(true);
        //开启驼峰命名
        strategy.setRestControllerStyle(true);

        // 写于父类中的公共字段
        strategy.setInclude(tables);
        strategy.setControllerMappingHyphenStyle(true);
        //strategy.setTablePrefix("t_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();

        return tables;
    }
}
